class Vue {
    constructor(options) {
        //保存选项
        this.$options = options;
        //通过选择器获取渲染的目标DOM元素
        this.$el = document.querySelector(options.el);
        //把选项里的data属性赋值给Vue实例的$data属性 
        this.$data = options.data;
        //初始化
        this.init();
    }
    init() {
        //数据代理 vm.msg = options.data.msg
        this.proxyData();
        this.compile(this.$el);
    }
    //数据代理 使得this.msg 等价于this.$data.msg
    proxyData() {
        //遍历this.$data上的所有的属性
        for (let key in this.$data) {
            //vm.msg  this[key]
            Object.defineProperty(this, key, {
                get() {//从Vm实例上取值的会去Vm实例上的$data属性上取值
                    return this.$data[key];
                },
                set(newVal) {//给vm实例赋值的时候会把值赋给vm实例的$data对象上
                    this.$data[key] = newVal;
                    this.compile();
                }
            })
        }
    }
    //编译模板
    compile(el) {
        //el.childNodes 获取当前elDOM元素的子元素的集合
        //通过Array.from变成数组
        //再根据节点的类型进行过滤，得到一个文本节点的数组
        const textNodes = Array.from(el.childNodes).filter(node=>node.nodeType === 3);
        //遍历文本节点的数组
        textNodes.forEach(node=>{
            //获取文本节点的内容
            const {textContent} = node;
            //把文本节点内容中的变量替换为实际数据对象的属性
            node.textContent = textContent.replace(/\{\{(.+?)\}\}/,(_,key)=>{
                return this[key];
            });
        });
        //等替换完所有的变量了，也就是说Vue已经编译结束了，就可以移除v-cloak属性，去掉display:none
        el.removeAttribute('v-cloak');
    }
}